package com.minishift.android.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;

/**
 * 
 * this class is exception log handler class.
 * @author Sirier
 *
 */
public class XExceptionHandler implements UncaughtExceptionHandler{

	private static final String PATH = Environment.getExternalStorageDirectory().getPath()+File.separator+"xlog";
	private static final String FILE_NAME = "exception";
	private static final String FILE_NAME_SUFFIX = ".trace"; 
	private static final boolean DUBUG = true;
	
	private static XExceptionHandler instance = null;
	
	private UncaughtExceptionHandler defaultHandler;
	private Context context;
	
	private XExceptionHandler(){}
	
	/**
	 * this method will get only object of XExceptionHandler.
	 * @return InitAction: only object of XExceptionHandler.
	 */
	public static XExceptionHandler getExceptionHandler(){
		if(null == instance){
			instance = new XExceptionHandler();
		}
		return instance;
	}
	
	/**
	 * this method will get only object of ExceptionHandler.
	 * @param context: current application.
	 */
	public void init(Context context){
		defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
		Thread.setDefaultUncaughtExceptionHandler(this);
		this.context = context.getApplicationContext(); 
	}

	/**
	 * Overriding the uncaughtException()
	 */
	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		try{
			printExceptionLogToSDCard(ex);
			uploadExceptionLogToServer();
		}catch(Exception e){
			XLog.e("Exception", e.toString());
		}
		ex.printStackTrace();
		if(defaultHandler != null)
			defaultHandler.uncaughtException(thread, ex);
		else
			XActivitiyManager.getXActivityManager().ApplicationExit(context);
	}
	
	/**
	 * this method will print exception logs to SDCard.
	 * @param ex: exception logs.
	 */
	@SuppressLint("SimpleDateFormat")
	private void printExceptionLogToSDCard(Throwable ex){
		if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
			if(DUBUG){
				XLog.w("Exception", "No SDCard!");
				return;
			}
		}
		File files = new File(PATH);
		if(!files.exists()){
			files.mkdirs();
		}
		long currentTime = System.currentTimeMillis();
		String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(currentTime));
		File file = new File(PATH + File.separator + FILE_NAME + time + FILE_NAME_SUFFIX);
		if(!file.exists()){
			try {
				file.createNewFile();
			} catch (IOException e) {
				XLog.e("Exception", e.toString());
			}
		}
		try{
			PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
			pw.println(time);
			printMobileInfo(pw);
			pw.println("");
			ex.printStackTrace(pw);
			pw.close();
		}catch(Exception e){
			XLog.e("Exception", e.toString());
		}
	}
	
	/**
	 * this method will print information about of current device. 
	 * @param pw: PrintWriter object.
	 */
	private void printMobileInfo(PrintWriter pw){
		PackageManager manager = context.getPackageManager();
		try {
			PackageInfo info = manager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
			pw.println("Application Version: " + info.versionName + "-" + info.versionCode);
			pw.println("OS Version: " + Build.VERSION.RELEASE + "-" + Build.VERSION.SDK_INT);
			pw.println("Vendor: " + Build.MANUFACTURER);
			pw.println("Model: " + Build.MODEL);
			pw.println("CPU ABI: " + Build.CPU_ABI);
		} catch (NameNotFoundException e) {
			XLog.e("Exception", e.toString());
		}
	}
	
	/**
	 * this method will upload the log to server.
	 * if you want to upload exception information to you server.
	 * should have a class extends this class, and overriding this method.
	 */
	protected void uploadExceptionLogToServer(){
		
	}
}
